library(here)
library(cowplot)
source(here("utils/data_processing.R"))
source(here("utils/figures.R"))

Import data

df_gpt3 <- read_csv(here("data/processed_diagnoses/diagnoses_gpt3.csv.gz"))
df_gpt4 <- read_csv(here("data/processed_diagnoses/diagnoses_gpt4.csv.gz"))
df_gpt4_icd <- read_csv(here("data/processed_diagnoses/diagnoses_gpt4_icd.csv.gz"))

Rank abundance

rank_abundance_plot(df_gpt3)+ggtitle("GPT3")

rank_abundance_plot(df_gpt4)+ggtitle("GPT4")

rank_abundance_plot(df_gpt4_icd)+ggtitle("GPT4 ICD")

Top diagnoses

n_diag <- 25
top_diagnosis_plot(df_gpt3, n_diag = n_diag)+ggtitle("GPT3")

top_diagnosis_plot(df_gpt4, n_diag = n_diag)+ggtitle("GPT4")

top_diagnosis_plot(df_gpt4_icd, n_diag = n_diag)+ggtitle("GPT4 ICD")

Cumulative top frequency

cumulative_frequency_plot(df_gpt3)+ggtitle("GPT3")

cumulative_frequency_plot(df_gpt4)+ggtitle("GPT4")

cumulative_frequency_plot(df_gpt4_icd)+ggtitle("GPT4 ICD")

Diagnosis rank list

diagnosis_rank_table(df_gpt3, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60))
diagnosis_rank_table(df_gpt4, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60)) 
diagnosis_rank_table(df_gpt4_icd, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60)) 
diagnosis_rank_table(df_gpt4, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60)) %>% 
  select(contains(c("diagnosis","mcas"))) %>% 
  head(6) %>% 
  mutate(diagnosis = str_to_sentence(diagnosis)) %>% 
  rename(Diagnosis = diagnosis, `MCAS consortium` = mcas_consortium, `MCAS alternative` = mcas_alternative) %>% 
  flextable() %>% 
  width(width = 2) %>% 
  align(j = 2:3, align = "center", part = "all")

Diagnosis

MCAS consortium

MCAS alternative

Anaphylaxis

1

84

Mastocytosis

14

107

Mast cell activation syndrome

24

65

Systemic mastocytosis

27

155

Mast cell disorders

72

942

Idiopathic anaphylaxis

122

937

NA

Diversity

set.seed(1234)
df_diversity_ci <- df_gpt4 %>% 
  count(criteria, diagnosis, sort = T) %>% 
  group_by(criteria) %>% 
  nest() %>% 
  mutate(boot = map(data, function(x){
    x <- deframe(x)
    x <- entropart::EntropyCI(entropart::Shannon, 
                              Simulations=500, 
                              Ns = x, q=1, 
                              Correction = "None")
    x
  })) %>% 
  mutate(shannon = map_dbl(data, 
                           ~log(entropart::Diversity(deframe(.), q=1, Correction="None")))) %>% # Calculate shannon with entropart
  mutate(boot = map(boot, ~quantile(., c(0.025,0.5,0.975)))) %>% 
  unnest_wider(boot)
================================================================================
================================================================================
================================================================================
================================================================================
================================================================================
================================================================================
Warning: There were 9006 warnings in `mutate()`.
The first warning was:
ℹ In argument: `boot = map(...)`.
ℹ In group 1: `criteria = "aha_kawasaki"`.
Caused by warning in `CheckentropartArguments()`:
! Function arguments cannot be checked because the entropart package is not attached. Add CheckArguments=FALSE to suppress this warning or run library('entropart')
ℹ Run ]8;;ide:run:dplyr::last_dplyr_warnings()dplyr::last_dplyr_warnings()]8;; to see the 9005 remaining warnings.Warning: There were 6 warnings in `mutate()`.
The first warning was:
ℹ In argument: `shannon = map_dbl(data, ~log(entropart::Diversity(deframe(.), q
  = 1, Correction = "None")))`.
ℹ In group 1: `criteria = "aha_kawasaki"`.
Caused by warning in `CheckentropartArguments()`:
! Function arguments cannot be checked because the entropart package is not attached. Add CheckArguments=FALSE to suppress this warning or run library('entropart')
ℹ Run ]8;;ide:run:dplyr::last_dplyr_warnings()dplyr::last_dplyr_warnings()]8;; to see the 5 remaining warnings.
df_diversity_ci

df_diversity_ci %>% 
  format_criteria() %>% 
  ggplot(aes(x = criteria, y = shannon))+
  geom_point(size = 1)+
  geom_errorbar(aes(ymin = `2.5%`, ymax = `97.5%`), width = 0.3)+
  theme_bw() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  labs(x = "", y = "Shannon diversity") 

Permutation testing

# Run outside of notebook
# Includes all 10,000 GPT iterations and 1000 bootstrap permutations 
# Contained in script source(here("scripts/diversity_analysis/permute_null_diversity_difference.R"))
library(here)
source(here("utils/data_processing.R"))
library(tidyverse)
library(vegan)
library(broom)
library(here)
library(furrr)
library(future.apply)

model <- "gpt4"
p <- 1000
i <- 10000

print("### Reading data")
read_path <- sprintf("data/processed_diagnoses/diagnoses_%s.csv.gz", model)
df <- read_csv(here(read_path))

print("### Calculating permutation")
perm_out <- difference_permutation_test(df, metric = "precision", permutations = p, gpt_iterations = i)

print("### Writing data")
write_path <- sprintf("data/diversity_analysis/precision_permutation_test_%s_p%s_i%s.RDS", model, p, i)
saveRDS(perm_out, here(write_path))
diversity_permutation_results <- readRDS(here("data/diversity_analysis/diversity_permutation_test_gpt4.RDS")) 
diversity_permutation_results
permutation_test_plot(diversity_permutation_results)

Similarity

Jaccard/Bray curtis

diagnosis_similarity_heatmap(df_gpt3, method = "bray")

diagnosis_similarity_heatmap(df_gpt4, method = "bray")

diagnosis_similarity_heatmap(df_gpt3)

diagnosis_similarity_heatmap(df_gpt4)

  • Bray-Curtis similarity measures the similarity of a given diagnostic criteria’s set of alternative diagnoses along with their frequencies.
  • This demonstrates that SLE criteria results in a very similar set and frequency of diagnoses, while the diagnoses associated with two MCAS criteria are as different from each other as they are from those generated by the criteria of other conditions.

PCA

diagnosis_pca_plot(df_gpt3) + ggtitle("GPT3")

diagnosis_pca_plot(df_gpt4) + ggtitle("GPT4")

Precision

  • Precision represents how similar each iteration of a 10-point differential diagnosis is with all other differential diagnoses from the same set of criteria.
  • I.e. how reproducible the 10-point differential diagnosis is for each criteria
  • Measured by obtaining the Bray-Curtis similarity values between all iterations within a criteria
# Script for calculating all Bray-Curtis similarity values within a criteria
# Found in source(here("scripts/diversity_analysis/calculate_precision.R"))
library(here)
source(here("utils/data_processing.R"))

models <- c("gpt3", "gpt4", "gpt4_icd")

for (m in models){
  print(sprintf("READING IN DATA FOR: %s", m))
  read_path <- sprintf("data/processed_diagnoses/diagnoses_%s.csv.gz", m)
  df <- read_csv(here(read_path))
  
  print(sprintf("CALCULATING PRECISION FOR: %s", m))
  df <- calculate_precision(df)
  
  print(sprintf("WRITING PRECISION DATA FOR: %s", m))
  out_path <- sprintf("data/diversity_analysis/diagnosis_precision_%s.csv.gz", m)
  write_csv(df, here(out_path))
}
df_precision <- vroom::vroom(here("data/diversity_analysis/diagnosis_precision_gpt4.csv.gz"))
Rows: 298535709 Columns: 2── Column specification ────────────────────────────────────────────────────────
Delimiter: ","
chr (1): criteria
dbl (1): distance
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
df_precision_summary <- df_precision %>% 
  mutate(distance = 1-distance) %>% # Convert to similarity
  summarise(mean_cl_normal(distance), .by = criteria)
df_precision_summary
calculate_boxplot_stats <- function(df){
  df %>% 
    nest(data = distance, .by = criteria) %>% 
    mutate(box = map(data, function(df){
      x <- boxplot.stats(df$distance)$stats
      x <- sort(x)
      names(x) <- c("min","lower","median","upper","max")
      return(x)
    })) %>% 
    select(-data) %>% 
    unnest_wider(box)
}



manual_box_plot <- function(df){
  df %>% 
    format_criteria() %>% 
    ggplot(aes(
      x = criteria,
      ymin = min,
      lower = lower,
      middle = median,
      upper = upper,
      ymax = max
    ))+
    geom_boxplot(stat = "identity") +
    theme_bw() +
    theme(axis.text.x = element_text(angle = 45, hjust = 1))+
    labs(x = "", y = "Bray-Curtis similarity")
}
df_precision_stats <- df_precision %>% 
  mutate(distance = 1-distance) %>% # Convert to similarity
  calculate_boxplot_stats()
df_precision_stats
manual_box_plot(df_precision_stats)

Permutation testing

# Run outside of notebook
# Tried multiple combinations of bootstrap permutations and gpt_iterations
# Because a single bray-curtis matrix of all 10,000 comparisons takes ~10 minutes
# Contained in following script:
# source(here("scripts/diversity_analysis/permute_null_precision_difference.R"))
model <- "gpt4"
p <- 1000
i <- 10000

print("### Reading data")
read_path <- sprintf("data/processed_diagnoses/diagnoses_%s.csv.gz", model)
df <- read_csv(here(read_path))

print("### Calculating permutation")
perm_out <- difference_permutation_test(df, metric = "precision", permutations = p, gpt_iterations = i)

print("### Writing data")
write_path <- sprintf("data/diversity_analysis/precision_permutation_test_%s_p%s_i%s.RDS", model, p, i)
saveRDS(perm_out, here())
readRDS(here("data/diversity_analysis/precision_permutation_test_gpt4_p1000_i10000.RDS"))
readRDS(here("data/diversity_analysis/precision_permutation_test_gpt4_p1000_i10000.RDS")) %>% permutation_test_plot()

iNEXT

inext_plots <- function(inext_obj){
  for (i in 1:3){
    plt <- iNEXT::ggiNEXT(inext_obj, type=i, facet.var="Assemblage", color.var="Assemblage") +
      theme_classic() + 
      scale_color_brewer(palette = "Set1") +
      theme(axis.text.x = element_text(angle = 90))+
      scale_color_brewer(palette = "Dark2")
    print(plt)
  }
}

readRDS(here("data/diversity_analysis/mcas_iNEXT_gpt4_e250000.RDS")) %>% inext_plots()
Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.

readRDS(here("data/diversity_analysis/mcas_iNEXT_dropSingle_gpt4_e200000.RDS")) %>% inext_plots()
Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.

readRDS(here("data/diversity_analysis/mcas_iNEXT_dropSingle_psuedoMinus_gpt4_e200000.RDS")) %>% inext_plots()
Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.

Final figures

2_Top_diagnoses

custom_labeler <- function(x, wrap_width=33) {
    x %>%
        str_replace("___.+$", "") %>%
        str_wrap(width = wrap_width)
}

plt_top <- top_diagnosis_plot(df_gpt4, n_diag = 25) + 
  theme(axis.text = element_text(size = 5, lineheight = 0.7), 
        strip.text = element_text(size = 7),
        axis.title = element_text(size = 9)) + 
  tidytext::scale_x_reordered(labels = custom_labeler)
Scale for x is already present.
Adding another scale for x, which will replace the existing scale.
plt_top

ggsave(plot=plt_top,filename=here("figures/3_Top_25_diagnoses.pdf"), width = 7.4, height = 6.5)

3A_Rank_abundance

plt_rank <- rank_abundance_plot(df_gpt4) +theme(legend.position = c(0.7,0.7))
plt_rank

3B_Cumulative_frequency

plt_cumulative <- cumulative_frequency_plot(df_gpt4) +
  labs(y = "Combined frequency\nof top 25 diagnoses")
plt_cumulative

3C_Diversity

plt_div <- df_diversity_ci %>% 
  format_criteria() %>% 
  ggplot(aes(x = criteria, y = shannon))+
  geom_point(size = 1)+
  geom_errorbar(aes(ymin = `2.5%`, ymax = `97.5%`), width = 0.3)+
  theme_bw() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  labs(x = "", y = "Shannon diversity") 
plt_div

3D_Precision

plt_precision <- manual_box_plot(df_precision_stats)
plt_precision

3_Compiled

plt_fig3 <- plot_grid(
  plot_grid(NULL),
  plot_grid(
    plt_rank,
    NULL,
    plt_cumulative,
    nrow = 1, 
    rel_widths = c(3,0.2,2),
    labels = c("A", "", "B"),
    vjust = 0.2
  ),
  plot_grid(NULL),
  plot_grid(
    plt_div,
    NULL,
    plt_precision,
    nrow = 1,
    rel_widths = c(1,0.1,1),
    labels = c("C", "", "D"),
    vjust = 0.2
  ),
  ncol = 1,
  rel_heights = c(0.05,1,0.05,1)
)
plt_fig3

ggsave(plot=plt_fig3,filename=here("figures/4_Diagnosis_diversity.pdf"), width = 6.5, height = 6)

Table

diagnosis_rank_table(df_gpt4, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60)) %>% 
  select(contains(c("diagnosis","mcas"))) %>% 
  head(6) %>% 
  mutate(diagnosis = str_to_sentence(diagnosis)) %>% 
  rename(Diagnosis = diagnosis, `MCAS consortium` = mcas_consortium, `MCAS alternative` = mcas_alternative) %>% 
  flextable() %>% 
  width(width = 2) %>% 
  align(j = 2:3, align = "center", part = "all") %>% 
  {print(., preview = "pdf");.}

Diagnosis

MCAS consortium

MCAS alternative

Anaphylaxis

1

84

Mastocytosis

14

107

Mast cell activation syndrome

24

65

Systemic mastocytosis

27

155

Mast cell disorders

72

942

Idiopathic anaphylaxis

122

937

Supplemental figures

plot_grid(
  top_diagnosis_plot(df_gpt3, n_diag = 25) + 
    theme(axis.text = element_text(size = 4.5, lineheight = 0.7), 
          strip.text = element_text(size = 7),
          axis.title = element_text(size = 9)) + 
    tidytext::scale_x_reordered(labels = custom_labeler),
  
  top_diagnosis_plot(df_gpt4_icd, n_diag = 25) + 
    theme(axis.text = element_text(size = 4, lineheight = 0.7), 
          strip.text = element_text(size = 7),
          axis.title = element_text(size = 9)) + 
    tidytext::scale_x_reordered(labels = ~custom_labeler(., wrap_width = 45)),
  ncol = 1,
  rel_heights = c(0.9,1),
  labels = c("A","B")
) %>% 
  {ggsave(plot=.,filename=here("figures/S_Top_diagnoses.pdf"), width = 7, height = 10);.}

plot_grid(
  rank_abundance_plot(df_gpt3) +theme(legend.position = c(0.7,0.7)),
  rank_abundance_plot(df_gpt4_icd) +theme(legend.position = c(0.7,0.7)),
  nrow = 1,
  labels = c("A","B")
) %>% 
  {ggsave(plot=.,filename=here("figures/S_Ranked_abundance.pdf"), width = 7.5, height = 3);.}

LS0tCnRpdGxlOiAiRGlhZ25vc2lzIGRpc3RyaWJ1dGlvbiBhbmFseXNpcyIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKLS0tCgpgYGB7ciwgbWVzc2FnZSA9IEZ9CmxpYnJhcnkoaGVyZSkKbGlicmFyeShjb3dwbG90KQpzb3VyY2UoaGVyZSgidXRpbHMvZGF0YV9wcm9jZXNzaW5nLlIiKSkKc291cmNlKGhlcmUoInV0aWxzL2ZpZ3VyZXMuUiIpKQpgYGAKCiMgSW1wb3J0IGRhdGEKYGBge3IsIG1lc3NhZ2U9Rn0KZGZfZ3B0MyA8LSByZWFkX2NzdihoZXJlKCJkYXRhL3Byb2Nlc3NlZF9kaWFnbm9zZXMvZGlhZ25vc2VzX2dwdDMuY3N2Lmd6IikpCmRmX2dwdDQgPC0gcmVhZF9jc3YoaGVyZSgiZGF0YS9wcm9jZXNzZWRfZGlhZ25vc2VzL2RpYWdub3Nlc19ncHQ0LmNzdi5neiIpKQpkZl9ncHQ0X2ljZCA8LSByZWFkX2NzdihoZXJlKCJkYXRhL3Byb2Nlc3NlZF9kaWFnbm9zZXMvZGlhZ25vc2VzX2dwdDRfaWNkLmNzdi5neiIpKQpgYGAKIyBSYW5rIGFidW5kYW5jZQpgYGB7cn0KcmFua19hYnVuZGFuY2VfcGxvdChkZl9ncHQzKStnZ3RpdGxlKCJHUFQzIikKcmFua19hYnVuZGFuY2VfcGxvdChkZl9ncHQ0KStnZ3RpdGxlKCJHUFQ0IikKcmFua19hYnVuZGFuY2VfcGxvdChkZl9ncHQ0X2ljZCkrZ2d0aXRsZSgiR1BUNCBJQ0QiKQpgYGAKCiMgVG9wIGRpYWdub3NlcwpgYGB7ciwgZmlnLndpZHRoID0gMTYsIGZpZy5oZWlnaHQgPSA4fQpuX2RpYWcgPC0gMjUKdG9wX2RpYWdub3Npc19wbG90KGRmX2dwdDMsIG5fZGlhZyA9IG5fZGlhZykrZ2d0aXRsZSgiR1BUMyIpCnRvcF9kaWFnbm9zaXNfcGxvdChkZl9ncHQ0LCBuX2RpYWcgPSBuX2RpYWcpK2dndGl0bGUoIkdQVDQiKQp0b3BfZGlhZ25vc2lzX3Bsb3QoZGZfZ3B0NF9pY2QsIG5fZGlhZyA9IG5fZGlhZykrZ2d0aXRsZSgiR1BUNCBJQ0QiKQpgYGAKCiMgQ3VtdWxhdGl2ZSB0b3AgZnJlcXVlbmN5CmBgYHtyLCBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zLjV9CmN1bXVsYXRpdmVfZnJlcXVlbmN5X3Bsb3QoZGZfZ3B0MykrZ2d0aXRsZSgiR1BUMyIpCmN1bXVsYXRpdmVfZnJlcXVlbmN5X3Bsb3QoZGZfZ3B0NCkrZ2d0aXRsZSgiR1BUNCIpCmN1bXVsYXRpdmVfZnJlcXVlbmN5X3Bsb3QoZGZfZ3B0NF9pY2QpK2dndGl0bGUoIkdQVDQgSUNEIikKYGBgCgojIERpYWdub3NpcyByYW5rIGxpc3QKYGBge3J9CmRpYWdub3Npc19yYW5rX3RhYmxlKGRmX2dwdDMsICJtYXN0IHxtYXN0b2N8YW5hcGh5bGF4aXMiKSAlPiUgbXV0YXRlKGRpYWdub3NpcyA9IHN1YnN0cihkaWFnbm9zaXMsIDEsIDYwKSkKZGlhZ25vc2lzX3JhbmtfdGFibGUoZGZfZ3B0NCwgIm1hc3QgfG1hc3RvY3xhbmFwaHlsYXhpcyIpICU+JSBtdXRhdGUoZGlhZ25vc2lzID0gc3Vic3RyKGRpYWdub3NpcywgMSwgNjApKSAKZGlhZ25vc2lzX3JhbmtfdGFibGUoZGZfZ3B0NF9pY2QsICJtYXN0IHxtYXN0b2N8YW5hcGh5bGF4aXMiKSAlPiUgbXV0YXRlKGRpYWdub3NpcyA9IHN1YnN0cihkaWFnbm9zaXMsIDEsIDYwKSkgCmBgYAoKYGBge3J9CmRpYWdub3Npc19yYW5rX3RhYmxlKGRmX2dwdDQsICJtYXN0IHxtYXN0b2N8YW5hcGh5bGF4aXMiKSAlPiUgbXV0YXRlKGRpYWdub3NpcyA9IHN1YnN0cihkaWFnbm9zaXMsIDEsIDYwKSkgJT4lIAogIHNlbGVjdChjb250YWlucyhjKCJkaWFnbm9zaXMiLCJtY2FzIikpKSAlPiUgCiAgaGVhZCg2KSAlPiUgCiAgbXV0YXRlKGRpYWdub3NpcyA9IHN0cl90b19zZW50ZW5jZShkaWFnbm9zaXMpKSAlPiUgCiAgcmVuYW1lKERpYWdub3NpcyA9IGRpYWdub3NpcywgYE1DQVMgY29uc29ydGl1bWAgPSBtY2FzX2NvbnNvcnRpdW0sIGBNQ0FTIGFsdGVybmF0aXZlYCA9IG1jYXNfYWx0ZXJuYXRpdmUpICU+JSAKICBmbGV4dGFibGUoKSAlPiUgCiAgd2lkdGgod2lkdGggPSAyKSAlPiUgCiAgYWxpZ24oaiA9IDI6MywgYWxpZ24gPSAiY2VudGVyIiwgcGFydCA9ICJhbGwiKQogIApgYGAKCgoKCiMgRGl2ZXJzaXR5CmBgYHtyLCBmaWcud2lkdGg9NCwgZmlnLmhlaWdodD0zLjV9CnNldC5zZWVkKDEyMzQpCmRmX2RpdmVyc2l0eV9jaSA8LSBkZl9ncHQ0ICU+JSAKICBjb3VudChjcml0ZXJpYSwgZGlhZ25vc2lzLCBzb3J0ID0gVCkgJT4lIAogIGdyb3VwX2J5KGNyaXRlcmlhKSAlPiUgCiAgbmVzdCgpICU+JSAKICBtdXRhdGUoYm9vdCA9IG1hcChkYXRhLCBmdW5jdGlvbih4KXsKICAgIHggPC0gZGVmcmFtZSh4KQogICAgeCA8LSBlbnRyb3BhcnQ6OkVudHJvcHlDSShlbnRyb3BhcnQ6OlNoYW5ub24sIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTaW11bGF0aW9ucz01MDAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBOcyA9IHgsIHE9MSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIENvcnJlY3Rpb24gPSAiTm9uZSIpCiAgICB4CiAgfSkpICU+JSAKICBtdXRhdGUoc2hhbm5vbiA9IG1hcF9kYmwoZGF0YSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIH5sb2coZW50cm9wYXJ0OjpEaXZlcnNpdHkoZGVmcmFtZSguKSwgcT0xLCBDb3JyZWN0aW9uPSJOb25lIikpKSkgJT4lICMgQ2FsY3VsYXRlIHNoYW5ub24gd2l0aCBlbnRyb3BhcnQKICBtdXRhdGUoYm9vdCA9IG1hcChib290LCB+cXVhbnRpbGUoLiwgYygwLjAyNSwwLjUsMC45NzUpKSkpICU+JSAKICB1bm5lc3Rfd2lkZXIoYm9vdCkKCmRmX2RpdmVyc2l0eV9jaQoKZGZfZGl2ZXJzaXR5X2NpICU+JSAKICBmb3JtYXRfY3JpdGVyaWEoKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gY3JpdGVyaWEsIHkgPSBzaGFubm9uKSkrCiAgZ2VvbV9wb2ludChzaXplID0gMSkrCiAgZ2VvbV9lcnJvcmJhcihhZXMoeW1pbiA9IGAyLjUlYCwgeW1heCA9IGA5Ny41JWApLCB3aWR0aCA9IDAuMykrCiAgdGhlbWVfYncoKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKwogIGxhYnMoeCA9ICIiLCB5ID0gIlNoYW5ub24gZGl2ZXJzaXR5IikgCmBgYAoKIyMjIFBlcm11dGF0aW9uIHRlc3RpbmcKCmBgYHtyLCBldmFsID0gRn0KIyBSdW4gb3V0c2lkZSBvZiBub3RlYm9vawojIEluY2x1ZGVzIGFsbCAxMCwwMDAgR1BUIGl0ZXJhdGlvbnMgYW5kIDEwMDAgYm9vdHN0cmFwIHBlcm11dGF0aW9ucyAKIyBDb250YWluZWQgaW4gc2NyaXB0IHNvdXJjZShoZXJlKCJzY3JpcHRzL2RpdmVyc2l0eV9hbmFseXNpcy9wZXJtdXRlX251bGxfZGl2ZXJzaXR5X2RpZmZlcmVuY2UuUiIpKQpsaWJyYXJ5KGhlcmUpCnNvdXJjZShoZXJlKCJ1dGlscy9kYXRhX3Byb2Nlc3NpbmcuUiIpKQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeSh2ZWdhbikKbGlicmFyeShicm9vbSkKbGlicmFyeShoZXJlKQpsaWJyYXJ5KGZ1cnJyKQpsaWJyYXJ5KGZ1dHVyZS5hcHBseSkKCm1vZGVsIDwtICJncHQ0IgpwIDwtIDEwMDAKaSA8LSAxMDAwMAoKcHJpbnQoIiMjIyBSZWFkaW5nIGRhdGEiKQpyZWFkX3BhdGggPC0gc3ByaW50ZigiZGF0YS9wcm9jZXNzZWRfZGlhZ25vc2VzL2RpYWdub3Nlc18lcy5jc3YuZ3oiLCBtb2RlbCkKZGYgPC0gcmVhZF9jc3YoaGVyZShyZWFkX3BhdGgpKQoKcHJpbnQoIiMjIyBDYWxjdWxhdGluZyBwZXJtdXRhdGlvbiIpCnBlcm1fb3V0IDwtIGRpZmZlcmVuY2VfcGVybXV0YXRpb25fdGVzdChkZiwgbWV0cmljID0gInByZWNpc2lvbiIsIHBlcm11dGF0aW9ucyA9IHAsIGdwdF9pdGVyYXRpb25zID0gaSkKCnByaW50KCIjIyMgV3JpdGluZyBkYXRhIikKd3JpdGVfcGF0aCA8LSBzcHJpbnRmKCJkYXRhL2RpdmVyc2l0eV9hbmFseXNpcy9wcmVjaXNpb25fcGVybXV0YXRpb25fdGVzdF8lc19wJXNfaSVzLlJEUyIsIG1vZGVsLCBwLCBpKQpzYXZlUkRTKHBlcm1fb3V0LCBoZXJlKHdyaXRlX3BhdGgpKQpgYGAKCmBgYHtyfQpkaXZlcnNpdHlfcGVybXV0YXRpb25fcmVzdWx0cyA8LSByZWFkUkRTKGhlcmUoImRhdGEvZGl2ZXJzaXR5X2FuYWx5c2lzL2RpdmVyc2l0eV9wZXJtdXRhdGlvbl90ZXN0X2dwdDQuUkRTIikpIApkaXZlcnNpdHlfcGVybXV0YXRpb25fcmVzdWx0cwpgYGAKYGBge3J9CnBlcm11dGF0aW9uX3Rlc3RfcGxvdChkaXZlcnNpdHlfcGVybXV0YXRpb25fcmVzdWx0cykKYGBgCgoKIyBTaW1pbGFyaXR5CgojIyMgSmFjY2FyZC9CcmF5IGN1cnRpcwpgYGB7ciwgZmlnLndpZHRoPTQuMjUsIGZpZy5oZWlnaHQ9My41fQpkaWFnbm9zaXNfc2ltaWxhcml0eV9oZWF0bWFwKGRmX2dwdDMsIG1ldGhvZCA9ICJicmF5IikKZGlhZ25vc2lzX3NpbWlsYXJpdHlfaGVhdG1hcChkZl9ncHQ0LCBtZXRob2QgPSAiYnJheSIpCmRpYWdub3Npc19zaW1pbGFyaXR5X2hlYXRtYXAoZGZfZ3B0MykKZGlhZ25vc2lzX3NpbWlsYXJpdHlfaGVhdG1hcChkZl9ncHQ0KQpgYGAKLSBCcmF5LUN1cnRpcyBzaW1pbGFyaXR5IG1lYXN1cmVzIHRoZSBzaW1pbGFyaXR5IG9mIGEgZ2l2ZW4gZGlhZ25vc3RpYyBjcml0ZXJpYeKAmXMgc2V0IG9mIGFsdGVybmF0aXZlIGRpYWdub3NlcyBhbG9uZyB3aXRoIHRoZWlyIGZyZXF1ZW5jaWVzLgotIFRoaXMgZGVtb25zdHJhdGVzIHRoYXQgU0xFIGNyaXRlcmlhIHJlc3VsdHMgaW4gYSB2ZXJ5IHNpbWlsYXIgc2V0IGFuZCBmcmVxdWVuY3kgb2YgZGlhZ25vc2VzLCB3aGlsZSB0aGUgZGlhZ25vc2VzIGFzc29jaWF0ZWQgd2l0aCB0d28gTUNBUyBjcml0ZXJpYSBhcmUgYXMgZGlmZmVyZW50IGZyb20gZWFjaCBvdGhlciBhcyB0aGV5IGFyZSBmcm9tIHRob3NlIGdlbmVyYXRlZCBieSB0aGUgY3JpdGVyaWEgb2Ygb3RoZXIgY29uZGl0aW9ucy4KCiMjIyBQQ0EKCmBgYHtyLCBmaWcud2lkdGg9NC4yNSwgZmlnLmhlaWdodD0zLjV9CmRpYWdub3Npc19wY2FfcGxvdChkZl9ncHQzKSArIGdndGl0bGUoIkdQVDMiKQpkaWFnbm9zaXNfcGNhX3Bsb3QoZGZfZ3B0NCkgKyBnZ3RpdGxlKCJHUFQ0IikKYGBgCiMgUHJlY2lzaW9uCgotIFByZWNpc2lvbiByZXByZXNlbnRzIGhvdyBzaW1pbGFyIGVhY2ggaXRlcmF0aW9uIG9mIGEgMTAtcG9pbnQgZGlmZmVyZW50aWFsIGRpYWdub3NpcyBpcyB3aXRoIGFsbCBvdGhlciBkaWZmZXJlbnRpYWwgZGlhZ25vc2VzIGZyb20gdGhlIHNhbWUgc2V0IG9mIGNyaXRlcmlhLiAKLSBJLmUuIGhvdyByZXByb2R1Y2libGUgdGhlIDEwLXBvaW50IGRpZmZlcmVudGlhbCBkaWFnbm9zaXMgaXMgZm9yIGVhY2ggY3JpdGVyaWEKLSBNZWFzdXJlZCBieSBvYnRhaW5pbmcgdGhlIEJyYXktQ3VydGlzIHNpbWlsYXJpdHkgdmFsdWVzIGJldHdlZW4gYWxsIGl0ZXJhdGlvbnMgd2l0aGluIGEgY3JpdGVyaWEKCmBgYHtyLCBldmFsPUZ9CiMgU2NyaXB0IGZvciBjYWxjdWxhdGluZyBhbGwgQnJheS1DdXJ0aXMgc2ltaWxhcml0eSB2YWx1ZXMgd2l0aGluIGEgY3JpdGVyaWEKIyBGb3VuZCBpbiBzb3VyY2UoaGVyZSgic2NyaXB0cy9kaXZlcnNpdHlfYW5hbHlzaXMvY2FsY3VsYXRlX3ByZWNpc2lvbi5SIikpCmxpYnJhcnkoaGVyZSkKc291cmNlKGhlcmUoInV0aWxzL2RhdGFfcHJvY2Vzc2luZy5SIikpCgptb2RlbHMgPC0gYygiZ3B0MyIsICJncHQ0IiwgImdwdDRfaWNkIikKCmZvciAobSBpbiBtb2RlbHMpewogIHByaW50KHNwcmludGYoIlJFQURJTkcgSU4gREFUQSBGT1I6ICVzIiwgbSkpCiAgcmVhZF9wYXRoIDwtIHNwcmludGYoImRhdGEvcHJvY2Vzc2VkX2RpYWdub3Nlcy9kaWFnbm9zZXNfJXMuY3N2Lmd6IiwgbSkKICBkZiA8LSByZWFkX2NzdihoZXJlKHJlYWRfcGF0aCkpCiAgCiAgcHJpbnQoc3ByaW50ZigiQ0FMQ1VMQVRJTkcgUFJFQ0lTSU9OIEZPUjogJXMiLCBtKSkKICBkZiA8LSBjYWxjdWxhdGVfcHJlY2lzaW9uKGRmKQogIAogIHByaW50KHNwcmludGYoIldSSVRJTkcgUFJFQ0lTSU9OIERBVEEgRk9SOiAlcyIsIG0pKQogIG91dF9wYXRoIDwtIHNwcmludGYoImRhdGEvZGl2ZXJzaXR5X2FuYWx5c2lzL2RpYWdub3Npc19wcmVjaXNpb25fJXMuY3N2Lmd6IiwgbSkKICB3cml0ZV9jc3YoZGYsIGhlcmUob3V0X3BhdGgpKQp9CmBgYAoKYGBge3J9CmRmX3ByZWNpc2lvbiA8LSB2cm9vbTo6dnJvb20oaGVyZSgiZGF0YS9kaXZlcnNpdHlfYW5hbHlzaXMvZGlhZ25vc2lzX3ByZWNpc2lvbl9ncHQ0LmNzdi5neiIpKQpgYGAKCmBgYHtyfQpkZl9wcmVjaXNpb25fc3VtbWFyeSA8LSBkZl9wcmVjaXNpb24gJT4lIAogIG11dGF0ZShkaXN0YW5jZSA9IDEtZGlzdGFuY2UpICU+JSAjIENvbnZlcnQgdG8gc2ltaWxhcml0eQogIHN1bW1hcmlzZShtZWFuX2NsX25vcm1hbChkaXN0YW5jZSksIC5ieSA9IGNyaXRlcmlhKQpkZl9wcmVjaXNpb25fc3VtbWFyeQpgYGAKCmBgYHtyLCBmaWcud2lkdGggPSAzLCBmaWcuaGVpZ2h0ID0gM30KY2FsY3VsYXRlX2JveHBsb3Rfc3RhdHMgPC0gZnVuY3Rpb24oZGYpewogIGRmICU+JSAKICAgIG5lc3QoZGF0YSA9IGRpc3RhbmNlLCAuYnkgPSBjcml0ZXJpYSkgJT4lIAogICAgbXV0YXRlKGJveCA9IG1hcChkYXRhLCBmdW5jdGlvbihkZil7CiAgICAgIHggPC0gYm94cGxvdC5zdGF0cyhkZiRkaXN0YW5jZSkkc3RhdHMKICAgICAgeCA8LSBzb3J0KHgpCiAgICAgIG5hbWVzKHgpIDwtIGMoIm1pbiIsImxvd2VyIiwibWVkaWFuIiwidXBwZXIiLCJtYXgiKQogICAgICByZXR1cm4oeCkKICAgIH0pKSAlPiUgCiAgICBzZWxlY3QoLWRhdGEpICU+JSAKICAgIHVubmVzdF93aWRlcihib3gpCn0KCgoKbWFudWFsX2JveF9wbG90IDwtIGZ1bmN0aW9uKGRmKXsKICBkZiAlPiUgCiAgICBmb3JtYXRfY3JpdGVyaWEoKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKAogICAgICB4ID0gY3JpdGVyaWEsCiAgICAgIHltaW4gPSBtaW4sCiAgICAgIGxvd2VyID0gbG93ZXIsCiAgICAgIG1pZGRsZSA9IG1lZGlhbiwKICAgICAgdXBwZXIgPSB1cHBlciwKICAgICAgeW1heCA9IG1heAogICAgKSkrCiAgICBnZW9tX2JveHBsb3Qoc3RhdCA9ICJpZGVudGl0eSIpICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkrCiAgICBsYWJzKHggPSAiIiwgeSA9ICJCcmF5LUN1cnRpcyBzaW1pbGFyaXR5IikKfQoKYGBgCgoKYGBge3J9CmRmX3ByZWNpc2lvbl9zdGF0cyA8LSBkZl9wcmVjaXNpb24gJT4lIAogIG11dGF0ZShkaXN0YW5jZSA9IDEtZGlzdGFuY2UpICU+JSAjIENvbnZlcnQgdG8gc2ltaWxhcml0eQogIGNhbGN1bGF0ZV9ib3hwbG90X3N0YXRzKCkKZGZfcHJlY2lzaW9uX3N0YXRzCmBgYApgYGB7ciwgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KbWFudWFsX2JveF9wbG90KGRmX3ByZWNpc2lvbl9zdGF0cykKYGBgCiMjIyBQZXJtdXRhdGlvbiB0ZXN0aW5nCgpgYGB7ciwgZXZhbCA9IEZ9CiMgUnVuIG91dHNpZGUgb2Ygbm90ZWJvb2sKIyBUcmllZCBtdWx0aXBsZSBjb21iaW5hdGlvbnMgb2YgYm9vdHN0cmFwIHBlcm11dGF0aW9ucyBhbmQgZ3B0X2l0ZXJhdGlvbnMKIyBCZWNhdXNlIGEgc2luZ2xlIGJyYXktY3VydGlzIG1hdHJpeCBvZiBhbGwgMTAsMDAwIGNvbXBhcmlzb25zIHRha2VzIH4xMCBtaW51dGVzCiMgQ29udGFpbmVkIGluIGZvbGxvd2luZyBzY3JpcHQ6CiMgc291cmNlKGhlcmUoInNjcmlwdHMvZGl2ZXJzaXR5X2FuYWx5c2lzL3Blcm11dGVfbnVsbF9wcmVjaXNpb25fZGlmZmVyZW5jZS5SIikpCm1vZGVsIDwtICJncHQ0IgpwIDwtIDEwMDAKaSA8LSAxMDAwMAoKcHJpbnQoIiMjIyBSZWFkaW5nIGRhdGEiKQpyZWFkX3BhdGggPC0gc3ByaW50ZigiZGF0YS9wcm9jZXNzZWRfZGlhZ25vc2VzL2RpYWdub3Nlc18lcy5jc3YuZ3oiLCBtb2RlbCkKZGYgPC0gcmVhZF9jc3YoaGVyZShyZWFkX3BhdGgpKQoKcHJpbnQoIiMjIyBDYWxjdWxhdGluZyBwZXJtdXRhdGlvbiIpCnBlcm1fb3V0IDwtIGRpZmZlcmVuY2VfcGVybXV0YXRpb25fdGVzdChkZiwgbWV0cmljID0gInByZWNpc2lvbiIsIHBlcm11dGF0aW9ucyA9IHAsIGdwdF9pdGVyYXRpb25zID0gaSkKCnByaW50KCIjIyMgV3JpdGluZyBkYXRhIikKd3JpdGVfcGF0aCA8LSBzcHJpbnRmKCJkYXRhL2RpdmVyc2l0eV9hbmFseXNpcy9wcmVjaXNpb25fcGVybXV0YXRpb25fdGVzdF8lc19wJXNfaSVzLlJEUyIsIG1vZGVsLCBwLCBpKQpzYXZlUkRTKHBlcm1fb3V0LCBoZXJlKCkpCmBgYAoKCmBgYHtyfQpyZWFkUkRTKGhlcmUoImRhdGEvZGl2ZXJzaXR5X2FuYWx5c2lzL3ByZWNpc2lvbl9wZXJtdXRhdGlvbl90ZXN0X2dwdDRfcDEwMDBfaTEwMDAwLlJEUyIpKQpgYGAKCgpgYGB7cn0KcmVhZFJEUyhoZXJlKCJkYXRhL2RpdmVyc2l0eV9hbmFseXNpcy9wcmVjaXNpb25fcGVybXV0YXRpb25fdGVzdF9ncHQ0X3AxMDAwX2kxMDAwMC5SRFMiKSkgJT4lIHBlcm11dGF0aW9uX3Rlc3RfcGxvdCgpCmBgYAoKCiMgaU5FWFQKCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0KaW5leHRfcGxvdHMgPC0gZnVuY3Rpb24oaW5leHRfb2JqKXsKICBmb3IgKGkgaW4gMTozKXsKICAgIHBsdCA8LSBpTkVYVDo6Z2dpTkVYVChpbmV4dF9vYmosIHR5cGU9aSwgZmFjZXQudmFyPSJBc3NlbWJsYWdlIiwgY29sb3IudmFyPSJBc3NlbWJsYWdlIikgKwogICAgICB0aGVtZV9jbGFzc2ljKCkgKyAKICAgICAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIpICsKICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpKwogICAgICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpCiAgICBwcmludChwbHQpCiAgfQp9CgpyZWFkUkRTKGhlcmUoImRhdGEvZGl2ZXJzaXR5X2FuYWx5c2lzL21jYXNfaU5FWFRfZ3B0NF9lMjUwMDAwLlJEUyIpKSAlPiUgaW5leHRfcGxvdHMoKQpyZWFkUkRTKGhlcmUoImRhdGEvZGl2ZXJzaXR5X2FuYWx5c2lzL21jYXNfaU5FWFRfZHJvcFNpbmdsZV9ncHQ0X2UyMDAwMDAuUkRTIikpICU+JSBpbmV4dF9wbG90cygpCnJlYWRSRFMoaGVyZSgiZGF0YS9kaXZlcnNpdHlfYW5hbHlzaXMvbWNhc19pTkVYVF9kcm9wU2luZ2xlX3BzdWVkb01pbnVzX2dwdDRfZTIwMDAwMC5SRFMiKSkgJT4lIGluZXh0X3Bsb3RzKCkKYGBgCgoKIyBGaW5hbCBmaWd1cmVzCgojIyMgMl9Ub3BfZGlhZ25vc2VzCmBgYHtyLCBmaWcud2lkdGg9Ny40LCBmaWcuaGVpZ2h0PTYuNX0KY3VzdG9tX2xhYmVsZXIgPC0gZnVuY3Rpb24oeCwgd3JhcF93aWR0aD0zMykgewogICAgeCAlPiUKICAgICAgICBzdHJfcmVwbGFjZSgiX19fLiskIiwgIiIpICU+JQogICAgICAgIHN0cl93cmFwKHdpZHRoID0gd3JhcF93aWR0aCkKfQoKcGx0X3RvcCA8LSB0b3BfZGlhZ25vc2lzX3Bsb3QoZGZfZ3B0NCwgbl9kaWFnID0gMjUpICsgCiAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA1LCBsaW5laGVpZ2h0ID0gMC43KSwgCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSkpICsgCiAgdGlkeXRleHQ6OnNjYWxlX3hfcmVvcmRlcmVkKGxhYmVscyA9IGN1c3RvbV9sYWJlbGVyKQpwbHRfdG9wCmBgYAoKYGBge3J9Cmdnc2F2ZShwbG90PXBsdF90b3AsZmlsZW5hbWU9aGVyZSgiZmlndXJlcy8zX1RvcF8yNV9kaWFnbm9zZXMucGRmIiksIHdpZHRoID0gNy40LCBoZWlnaHQgPSA2LjUpCmBgYAoKCiMjIyAzQV9SYW5rX2FidW5kYW5jZQpgYGB7ciwgZmlnLndpZHRoPTMuNSwgZmlnLmhlaWdodD0yLjV9CnBsdF9yYW5rIDwtIHJhbmtfYWJ1bmRhbmNlX3Bsb3QoZGZfZ3B0NCkgK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC43LDAuNykpCnBsdF9yYW5rCmBgYAoKIyMjIDNCX0N1bXVsYXRpdmVfZnJlcXVlbmN5CgpgYGB7ciwgZmlnLndpZHRoPTIuNSwgZmlnLmhlaWdodD0yLjV9CnBsdF9jdW11bGF0aXZlIDwtIGN1bXVsYXRpdmVfZnJlcXVlbmN5X3Bsb3QoZGZfZ3B0NCkgKwogIGxhYnMoeSA9ICJDb21iaW5lZCBmcmVxdWVuY3lcbm9mIHRvcCAyNSBkaWFnbm9zZXMiKQpwbHRfY3VtdWxhdGl2ZQpgYGAKCgoKIyMjIDNDX0RpdmVyc2l0eQpgYGB7ciwgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KcGx0X2RpdiA8LSBkZl9kaXZlcnNpdHlfY2kgJT4lIAogIGZvcm1hdF9jcml0ZXJpYSgpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBjcml0ZXJpYSwgeSA9IHNoYW5ub24pKSsKICBnZW9tX3BvaW50KHNpemUgPSAxKSsKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gYDIuNSVgLCB5bWF4ID0gYDk3LjUlYCksIHdpZHRoID0gMC4zKSsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArCiAgbGFicyh4ID0gIiIsIHkgPSAiU2hhbm5vbiBkaXZlcnNpdHkiKSAKcGx0X2RpdgpgYGAKIyMjIDNEX1ByZWNpc2lvbgpgYGB7ciwgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KcGx0X3ByZWNpc2lvbiA8LSBtYW51YWxfYm94X3Bsb3QoZGZfcHJlY2lzaW9uX3N0YXRzKQpwbHRfcHJlY2lzaW9uCmBgYAojIyMgM19Db21waWxlZCAKCmBgYHtyLCBmaWcud2lkdGg9Ni41LCBmaWcuaGVpZ2h0PTZ9CnBsdF9maWczIDwtIHBsb3RfZ3JpZCgKICBwbG90X2dyaWQoTlVMTCksCiAgcGxvdF9ncmlkKAogICAgcGx0X3JhbmssCiAgICBOVUxMLAogICAgcGx0X2N1bXVsYXRpdmUsCiAgICBucm93ID0gMSwgCiAgICByZWxfd2lkdGhzID0gYygzLDAuMiwyKSwKICAgIGxhYmVscyA9IGMoIkEiLCAiIiwgIkIiKSwKICAgIHZqdXN0ID0gMC4yCiAgKSwKICBwbG90X2dyaWQoTlVMTCksCiAgcGxvdF9ncmlkKAogICAgcGx0X2RpdiwKICAgIE5VTEwsCiAgICBwbHRfcHJlY2lzaW9uLAogICAgbnJvdyA9IDEsCiAgICByZWxfd2lkdGhzID0gYygxLDAuMSwxKSwKICAgIGxhYmVscyA9IGMoIkMiLCAiIiwgIkQiKSwKICAgIHZqdXN0ID0gMC4yCiAgKSwKICBuY29sID0gMSwKICByZWxfaGVpZ2h0cyA9IGMoMC4wNSwxLDAuMDUsMSkKKQpwbHRfZmlnMwpnZ3NhdmUocGxvdD1wbHRfZmlnMyxmaWxlbmFtZT1oZXJlKCJmaWd1cmVzLzRfRGlhZ25vc2lzX2RpdmVyc2l0eS5wZGYiKSwgd2lkdGggPSA2LjUsIGhlaWdodCA9IDYpCmBgYAoKIyMjIFRhYmxlCgpgYGB7ciwgbWVzc2FnZSA9IEYsIHdhcm5pbmc9RkFMU0V9CmRpYWdub3Npc19yYW5rX3RhYmxlKGRmX2dwdDQsICJtYXN0IHxtYXN0b2N8YW5hcGh5bGF4aXMiKSAlPiUgbXV0YXRlKGRpYWdub3NpcyA9IHN1YnN0cihkaWFnbm9zaXMsIDEsIDYwKSkgJT4lIAogIHNlbGVjdChjb250YWlucyhjKCJkaWFnbm9zaXMiLCJtY2FzIikpKSAlPiUgCiAgaGVhZCg2KSAlPiUgCiAgbXV0YXRlKGRpYWdub3NpcyA9IHN0cl90b19zZW50ZW5jZShkaWFnbm9zaXMpKSAlPiUgCiAgcmVuYW1lKERpYWdub3NpcyA9IGRpYWdub3NpcywgYE1DQVMgY29uc29ydGl1bWAgPSBtY2FzX2NvbnNvcnRpdW0sIGBNQ0FTIGFsdGVybmF0aXZlYCA9IG1jYXNfYWx0ZXJuYXRpdmUpICU+JSAKICBmbGV4dGFibGUoKSAlPiUgCiAgd2lkdGgod2lkdGggPSAyKSAlPiUgCiAgYWxpZ24oaiA9IDI6MywgYWxpZ24gPSAiY2VudGVyIiwgcGFydCA9ICJhbGwiKSAlPiUgCiAge3ByaW50KC4sIHByZXZpZXcgPSAicGRmIik7Ln0KYGBgCgojIyMgU3VwcGxlbWVudGFsIGZpZ3VyZXMKCmBgYHtyLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD0xMCwgbWVzc2FnZSA9IEZ9CnBsb3RfZ3JpZCgKICB0b3BfZGlhZ25vc2lzX3Bsb3QoZGZfZ3B0Mywgbl9kaWFnID0gMjUpICsgCiAgICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDQuNSwgbGluZWhlaWdodCA9IDAuNyksIAogICAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSkgKyAKICAgIHRpZHl0ZXh0OjpzY2FsZV94X3Jlb3JkZXJlZChsYWJlbHMgPSBjdXN0b21fbGFiZWxlciksCiAgCiAgdG9wX2RpYWdub3Npc19wbG90KGRmX2dwdDRfaWNkLCBuX2RpYWcgPSAyNSkgKyAKICAgIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNCwgbGluZWhlaWdodCA9IDAuNyksIAogICAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSkgKyAKICAgIHRpZHl0ZXh0OjpzY2FsZV94X3Jlb3JkZXJlZChsYWJlbHMgPSB+Y3VzdG9tX2xhYmVsZXIoLiwgd3JhcF93aWR0aCA9IDQ1KSksCiAgbmNvbCA9IDEsCiAgcmVsX2hlaWdodHMgPSBjKDAuOSwxKSwKICBsYWJlbHMgPSBjKCJBIiwiQiIpCikgJT4lIAogIHtnZ3NhdmUocGxvdD0uLGZpbGVuYW1lPWhlcmUoImZpZ3VyZXMvU19Ub3BfZGlhZ25vc2VzLnBkZiIpLCB3aWR0aCA9IDcsIGhlaWdodCA9IDEwKTsufQpgYGAKYGBge3IsIGZpZy53aWR0aD03LjUsIGZpZy5oZWlnaHQ9M30KcGxvdF9ncmlkKAogIHJhbmtfYWJ1bmRhbmNlX3Bsb3QoZGZfZ3B0MykgK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC43LDAuNykpLAogIHJhbmtfYWJ1bmRhbmNlX3Bsb3QoZGZfZ3B0NF9pY2QpICt0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuNywwLjcpKSwKICBucm93ID0gMSwKICBsYWJlbHMgPSBjKCJBIiwiQiIpCikgJT4lIAogIHtnZ3NhdmUocGxvdD0uLGZpbGVuYW1lPWhlcmUoImZpZ3VyZXMvU19SYW5rZWRfYWJ1bmRhbmNlLnBkZiIpLCB3aWR0aCA9IDcuNSwgaGVpZ2h0ID0gMyk7Ln0KYGBgCgoKCg==